/*
 * Open LiveReplay Server - Live replay server for Supreme Commander
 * 
 * Copyright (C) 2009, 2009 Open LiveReplay Server Project
 * 
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 * 
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details:
 * http://www.gnu.org/copyleft/lesser.html#TOC3
 */
package net.galacticwar.replayserver;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * In order to limits the usage of this server, this filter 
 * allows users to send their replays only if they are registered by the administrator.
 * <br>
 * <br>
 * This filter can be disabled
 * 
 * @author Yoann Meste (aka Mancer)
 *
 */
public class ReplayFilter {
	/**
	 * Logger for this class
	 */
	private static final Logger logger = Logger.getLogger(ReplayFilter.class.getName());

	private static final int MAX_NAME_LENGTH = 50;
	
	private static final ReplayFilter instance = new ReplayFilter();
	
	//private boolean enabled = true;
	
	//Batto : disable filter.
	private boolean enabled = false;
	
	private List<String> allowedNames = new ArrayList<String>();
	
	private ReplayFilter() {
		logger.log(Level.INFO, "Initiliazing Replay filter");
		try {
			init();
		} catch (IOException e) {
			logger.log(Level.WARNING, "Impossible to read config file", e);
		}
	}
	
	/**
	 * Returns if this filter is enabled
	 * @return
	 */
	public boolean isEnabled() {
		return enabled;
	}
	
	/**
	 * Activates this filter
	 * @param enabled
	 */
	public void setEnabled(boolean enabled) {
		this.enabled = enabled;
	}
	
	/**
	 * Register a new allowed name
	 * @param name 
	 */
	public void registerName(String name) {
		allowedNames.add(name);
		try {
			saveToFile();
		} catch (IOException e) {
			logger.log(Level.WARNING, "Impossible to save config file", e);
		}
		logger.log(Level.INFO, "Name {0} added in the allowed list", name);
	}
	
	/**
	 * Removed the allowed name
	 * @param name 
	 */
	public void unRegisterName(String name) {
		allowedNames.remove(name);
		try {
			saveToFile();
		} catch (IOException e) {
			logger.log(Level.WARNING, "Impossible to save config file", e);
		}
		logger.log(Level.INFO, "Name {0} removed from the allowed list", name);
	}
	
	/**
	 * Returns the complete list of all allowed names
	 * @return
	 */
	public List<String> getAllowedNames() {
		return Collections.unmodifiableList(allowedNames);
	}
	
	/**
	 * If this filter is enabled, it will look if one the player's name is in the allowed list
	 * @param replay
	 * @return if the replay is allowed to be saved and broadcasted
	 */
	public boolean isReplayAllowed(Replay replay){
		if ( ! enabled) {
			return true;
		}
		for (Player player : replay.getPlayers()) {
			if (allowedNames.contains(player.getName())) {
				return true;
			}
		}
		return false;
	}
	
	/**
	 * Checks if the replay name is not too long and ends with SCFAReplay
	 * 
	 * @param replayName
	 * @return boolean if the name is valid
	 */
	public boolean isNameValid(String replayName){
		//Check the name length
		if (replayName.length() > MAX_NAME_LENGTH) {
			logger.log(Level.WARNING, "The replay name {0} is too long", replayName);
			return false;
		}

		//Check if the replay name is valid
		if (replayName.endsWith(".SCFAReplay")==false) {
			logger.log(Level.WARNING, "The replay name {0} should finish with SCFAReplay", replayName);
			return false;
		}

		//TODO add restrcition on characters here...
//		
//		final String  restriction= "[a-z].SCFAReplay";
//		boolean match =  Pattern.matches(restriction, replayName);
//		if (! match) {
//			return false;
//		}
		
		
		return true;

	}
	
	/**
	 * Basic implementation of reading allowed name list from disk
	 * <br>
	 * TODO improve file format
	 * 
	 * @throws IOException
	 */
	private void init() throws IOException
	{
		//BATTO : if the filter is not enabled, we don't have to read anything.
		//causes error at launch if file does not exist (??)
//		if (!enabled)
//		{
//			logger.log(Level.INFO, "ReplayFilter not enabled, ignoring Registered Names.");
//			return;
//		}
		
		logger.log(Level.INFO, "Reading allowed name list from disk");
		
		File f = new File("RegisteredNames.txt");
		if (f.exists()) {
			BufferedReader in = new BufferedReader(new FileReader(f));
			
			String str;
			while ((str=in.readLine()) != null) {
				allowedNames.add(str);
			}
			in.close();
		}
		else{
			f.createNewFile();
		}
	}
	
	/**
	 * Basic implementation for saving allowed name list from disk
	 * <br>
	 * TODO improve file format
	 * 
	 * @throws IOException
	 */
	private void saveToFile() throws IOException{
		File f = new File("RegisteredNames.txt");
		
		if (! f.exists()) {
			f.createNewFile();
		}
		BufferedWriter out = new BufferedWriter(new FileWriter(f, false));
		for (String name : allowedNames) {
			out.write(name + "\r\n");
		}
		out.close();
		
		logger.log(Level.INFO, "Allowed name list saved to disk");
	}
	
	public static ReplayFilter getInstance() {
		return instance;
	}
}
